package com.example.main.utils;


import com.litesuits.common.io.FileUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class HeaderByteUtils {
    /*
    文件个数 byte

    数据类型 byte
    该数据长度 4个byte
    文件里偏移量开始位置 4个byte

    数据
     */

    private static final String TAG = "HeaderUtils";

    public static final int HEADER_ITEME_SIZE = 9;

    public final static int TYPE_JSON = 1;//JSON文本
    public final static int TYPE_IMAGE = 2;//图片base64

    /**
     * 添加完成内容 (现在用了hashmap只能保存一种类型数据)
     *
     * @param byteContentBeanList
     * @return
     */
    public static byte[] addFullContent(List<ByteContentBean> byteContentBeanList) {
        byte[] headerResult = HeaderByteUtils.addHeaders(byteContentBeanList);
        for (int i = 0; i < byteContentBeanList.size(); i++) {
            headerResult = concat(headerResult, byteContentBeanList.get(i).getData());
        }
        return headerResult;
    }

    /**
     * 组成头
     *
     * @param byteContentBeanList
     * @return
     */
    private static byte[] addHeaders(List<ByteContentBean> byteContentBeanList) {
        byte[] result = new byte[0];
        for (int i = 0; i < byteContentBeanList.size(); i++) {
            result = concat(result, addHeader(byteContentBeanList.get(i).getType(), byteContentBeanList.get(i).getData()));
        }

        byte[] typeNum = {(byte) byteContentBeanList.size()};
        result = concat(typeNum, result);//添加头数量第一个字节

        int header = result.length;
        int offset = 0;
        for (int i = 0; i < byteContentBeanList.size(); i++) {
            int ov = header + offset;
            result[6 + HEADER_ITEME_SIZE * i] = (byte) (ov >> 24 & 0xff);
            result[7 + HEADER_ITEME_SIZE * i] = (byte) (ov >> 16 & 0xff);
            result[8 + HEADER_ITEME_SIZE * i] = (byte) (ov >> 8 & 0xff);
            result[9 + HEADER_ITEME_SIZE * i] = (byte) (ov & 0xff);
            int sizeTemp = ((result[2 + HEADER_ITEME_SIZE * i] & 0xff) << 24)
                    + ((result[3 + HEADER_ITEME_SIZE * i] & 0xff) << 16)
                    + ((result[4 + HEADER_ITEME_SIZE * i] & 0xff) << 8)
                    + (result[5 + HEADER_ITEME_SIZE * i] & 0xff);
            offset += sizeTemp;
        }

        return result;
    }

    /**
     * 解析头
     *
     * @param file
     * @return
     */
    private static byte[] parseHeader(File file) {
        byte[] result = null;
        try {
            FileInputStream fileInputStream = FileUtils.openInputStream(file);
            if (fileInputStream.available() > 0) {
                result = new byte[1];
                result[0] = (byte) fileInputStream.read();
                byte[] readbuffer = new byte[result[0] * HEADER_ITEME_SIZE];
                if (fileInputStream.read(readbuffer, 0, readbuffer.length) > 0) {
                    result = concat(result, readbuffer);
                }
            }
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 合并两个数组
     *
     * @param first
     * @param second
     * @return
     */
    private static byte[] concat(byte[] first, byte[] second) {
        byte[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

    /**
     * 添加头
     *
     * @param headerType
     * @param content
     * @return
     */
    private static byte[] addHeader(int headerType, byte[] content) {
        int size = content.length;
        byte[] header = new byte[HEADER_ITEME_SIZE];
        header[0] = (byte) headerType;
        header[1] = (byte) ((size >> 24) & 0xff);
        header[2] = (byte) ((size >> 16) & 0xff);
        header[3] = (byte) ((size >> 8) & 0xff);
        header[4] = (byte) ((size) & 0xff);
        return header;
    }

    /**
     * @param file
     * @return int[]{类型，长度，字节起始位}
     */
    public static List<int[]> parseHeaderItem(File file) {
        byte[] header = parseHeader(file);
        List<int[]> headerResult = new ArrayList<>();
        byte[] dest = new byte[header.length - 1];
        System.arraycopy(header, 1, dest, 0, dest.length);
        for (int i = 0; i < header[0]; i++) {
            int[] result = new int[3];
            result[0] = dest[0 + i * HEADER_ITEME_SIZE];
            result[1] = ((dest[1 + i * HEADER_ITEME_SIZE] & 0xff) << 24)
                    + ((dest[2 + i * HEADER_ITEME_SIZE] & 0xff) << 16)
                    + ((dest[3 + i * HEADER_ITEME_SIZE] & 0xff) << 8)
                    + (dest[4 + i * HEADER_ITEME_SIZE] & 0xff);
            result[2] = ((dest[5 + i * HEADER_ITEME_SIZE] & 0xff) << 24)
                    + ((dest[6 + i * HEADER_ITEME_SIZE] & 0xff) << 16)
                    + ((dest[7 + i * HEADER_ITEME_SIZE] & 0xff) << 8)
                    + (dest[8 + i * HEADER_ITEME_SIZE] & 0xff);
            headerResult.add(result);
        }
        return headerResult;
    }

    /**
     * @param type
     * @param headerInfoList
     * @param fullContent
     * @return
     */
    public static List<byte[]> parseForType(
            int type,
            List<int[]> headerInfoList,
            byte[] fullContent) {
        List<byte[]> resultValue = new ArrayList<>();
        for (int i = 0; i < headerInfoList.size(); i++) {
            if (type == headerInfoList.get(i)[0]) {
                byte[] dest = new byte[headerInfoList.get(i)[1]];
                System.arraycopy(fullContent, headerInfoList.get(i)[2], dest, 0, dest.length);
                resultValue.add(dest);
            }
        }
        return resultValue;
    }

    public static class ByteContentBean implements Serializable {
        private int type;
        private byte[] data;

        public ByteContentBean(int type, byte[] data) {
            this.type = type;
            this.data = data;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }

        public byte[] getData() {
            return data;
        }

        public void setData(byte[] data) {
            this.data = data;
        }
    }
}
